﻿@page "/"
@using ExampleBlazor.Data
@using InfluxDB.Client.Api.Domain
@using InfluxDB.Client.Core.Flux.Domain
@using Radzen
@using System.Globalization

@inject IJSRuntime JsRuntime

<PageTitle>Index</PageTitle>

<div class="row my-xl-3">
    <div class="col-xl-4 col-lg-4 pr-xl-2 my-1 my-xl-0">
        <RadzenCard class="pb-5 fill">
            <div class="row">
                <div class="col-9">
                    <h2 class="h1_blue">Client<span class="h1_pink">Settings</span></h2>
                </div>
                <div class="col-3 text-end">
                    <RadzenButton Click="CheckConnection" Icon="@_buttonIcon" IsBusy="@CheckConnectionBusy"
                                  ButtonStyle="CheckConnectionButtonStyle"/>
                </div>
            </div>
            <hr/>
            <div class="row">
                <div class="col-12">
                    <label>Url</label>
                    <input class="input-fill-width" @bind="_client!.Url"/>
                    <label class="mt-3">Token</label>
                    <input class="input-fill-width" @bind="_client!.Token"/>
                    <label class="mt-3">Organization</label>
                    <input class="input-fill-width" @bind="_client!.Org"/>
                </div>
            </div>
        </RadzenCard>
    </div>
    <div class="col-xl-8 col-lg-8 pl-xl-2 my-1 my-xl-0">
        <RadzenCard class="pb-5 fill">
            <div class="row">
                <div class="col-6">
                    <h2 class="h1_blue">Device<span class="h1_pink">Registration</span></h2>
                </div>
                <div class="col-6 text-end">
                    @if (_bucketList == null)
                    {
                        <select class="card-select" @bind="SelectedBucket">
                            <option>-- bucket --</option>
                        </select>
                    }
                    else
                    {
                        <select class="card-select" @bind="SelectedBucket">
                            <option>-- bucket --</option>

                            @foreach (var bucket in _bucketList)
                            {
                                <option value="@bucket.Name">@bucket.Name</option>
                            }
                        </select>
                    }
                    <input class="card-select" placeholder="New DeviceId" @bind="NewDevice"/>
                    <RadzenButton Click="RegisterDevice" Icon="add_circle_outline" IsBusy="@RegisterDeviceBusy"
                                  ButtonStyle="ButtonStyle.Light"/>

                    <RadzenButton Click="RefreshDevices" Icon="refresh" IsBusy="@RefreshDevicesBusy"
                                  ButtonStyle="ButtonStyle.Light"/>
                </div>
            </div>
            <hr/>
            <div class="row">
                <div class="col-12">
                    <RadzenDataGrid Data="@DeviceList" TItem="FluxRecord" PagerPosition="PagerPosition.Bottom" AllowPaging="true" AllowSorting="false" PageSize="3">
                        <Columns>
                            <RadzenDataGridColumn TItem="FluxRecord" Property="deviceId" Title="DeviceID">
                                <Template Context="record">
                                    @record!.Values.FirstOrDefault(val => val.Key == "deviceId").Value
                                </Template>
                            </RadzenDataGridColumn>
                            <RadzenDataGridColumn TItem="FluxRecord" Property="registrationTime" Title="Registration Time">
                                <Template Context="record">
                                    @FormatDateTime(record!.Values.FirstOrDefault(val => val.Key == "_time").Value)
                                </Template>
                            </RadzenDataGridColumn>
                            <RadzenDataGridColumn TItem="FluxRecord" Property="delete" Title="" Width="60px">
                                <Template Context="record">
                                    <RadzenButton Click="() => RemoveDevice(record)" IsBusy="RemoveDeviceBusy" Icon="delete" ButtonStyle="ButtonStyle.Light"/>
                                </Template>
                            </RadzenDataGridColumn>

                        </Columns>
                    </RadzenDataGrid>
                </div>
            </div>
        </RadzenCard>
    </div>
</div>

<div class="row my-xl-3 my-1">
    <div class="col-xl-12">
        <RadzenCard class="pb-5 fill">
            <div class="row">
                <div class="col-4">
                    <h2 class="h1_blue">Device<span class="h1_pink">Dashboard</span></h2>
                </div>
                <div class="col-8 text-end">
                    @if (DeviceList == null)
                    {
                        <select class="card-select" @bind="SelectedDevice">
                            <option>-- deviceId --</option>
                        </select>
                    }
                    else
                    {
                        <select class="card-select" @bind="SelectedDevice">
                            <option>-- deviceId --</option>

                            @foreach (var device in DeviceList)
                            {
                                <option value="@device!.Values.First(rec => rec.Key == "deviceId").Value">@device.Values.First(rec => rec.Key == "deviceId").Value</option>
                            }
                        </select>
                    }
                    <RadzenButton Click="WriteEmulatedData" Icon="edit_note" IsBusy="@WriteEmulatedDataBusy"
                                  ButtonStyle="ButtonStyle.Light"/>
                    <RadzenButton Click="RefreshData" Icon="refresh" IsBusy="@RefreshDataBusy"
                                  ButtonStyle="ButtonStyle.Light"/>
                </div>
            </div>
            <hr/>
            <div class="row">
                @if (_chartDataList != null)
                {
                    foreach (var data in _chartDataList)
                    {
                        <div class="my-col-xl my-col-lg my-col-md my-col-xs">
                            <div class="text-center">
                                <text class="chart-label">@data.Name</text>
                            </div>
                            <RadzenRadialGauge Style="width: 100%; min-height: 250px; height: 250px">
                                <RadzenRadialGaugeScale StartAngle="-120" EndAngle="120" Step="data.Step" Min="data.Min"
                                                        Max="data.Max" MinorStep="data.MinorStep"
                                                        TickPosition=GaugeTickPosition.Inside TickLength="18" MinorTickLength="16">
                                    <RadzenRadialGaugeScalePointer Value=data.Value Length="0.7" ShowValue=true>
                                        <Template Context="pointer">
                                            <h4 class="chart-pointer">
                                                @pointer.Value <sup>@data.Sup</sup>
                                            </h4>
                                        </Template>
                                    </RadzenRadialGaugeScalePointer>
                                    <RadzenRadialGaugeScaleRange From=data.Min To=data.Value Fill="#d30971" Height="13"/>
                                    <RadzenRadialGaugeScaleRange From=data.Value To=data.Max Fill="#e6ecef" Height="13"/>
                                </RadzenRadialGaugeScale>
                            </RadzenRadialGauge>
                        </div>
                    }
                }

            </div>
            <div class="row">
                <div class="col-12">
                    <RadzenDataGrid Data="@Measurements" TItem="FluxTable" PagerPosition="PagerPosition.Bottom" AllowPaging="true" AllowSorting="false">
                        <Columns>
                            <RadzenDataGridColumn TItem="FluxTable" Property="Field" Title="Field">
                                <Template Context="table">
                                    @table.Records.FirstOrDefault()?.Values.FirstOrDefault(rec => rec.Key == "_field").Value
                                </Template>
                            </RadzenDataGridColumn>
                            <RadzenDataGridColumn TItem="FluxTable" Property="Min" Title="Min">
                                <Template Context="table">
                                    @table.Records.FirstOrDefault()?.Values.FirstOrDefault(rec => rec.Key == "minValue").Value
                                </Template>
                            </RadzenDataGridColumn>
                            <RadzenDataGridColumn TItem="FluxTable" Property="Max" Title="Max">
                                <Template Context="table">
                                    @table.Records.FirstOrDefault()?.Values.FirstOrDefault(rec => rec.Key == "maxValue").Value
                                </Template>
                            </RadzenDataGridColumn>
                            <RadzenDataGridColumn TItem="FluxTable" Property="MaxTime" Title="Max time">
                                <Template Context="table">
                                    @FormatDateTime(table.Records.FirstOrDefault()?.Values.FirstOrDefault(rec => rec.Key == "maxTime").Value)
                                </Template>
                            </RadzenDataGridColumn>
                            <RadzenDataGridColumn TItem="FluxTable" Property="EntryCount" Title="Entry count">
                                <Template Context="table">
                                    @table.Records.FirstOrDefault()?.Values.FirstOrDefault(rec => rec.Key == "count").Value
                                </Template>
                            </RadzenDataGridColumn>
                        </Columns>
                    </RadzenDataGrid>
                </div>
            </div>
        </RadzenCard>
    </div>
</div>

@code {

    protected override async Task OnInitializedAsync()
    {
        _chartDataList = new List<ChartData>
        {
            new("Temperature", "°C", 0, 50, StateHasChanged),
            new("Humidity", "%", 0, 100, StateHasChanged),
            new("Pressure", "hPa", 970, 1050, StateHasChanged),
            new("CO2", "ppm", 400, 3000, StateHasChanged),
            new("TVOC", "ppm", 200, 2000, StateHasChanged)
        };

        _client = new Client(InfluxModel.Client.Url, InfluxModel.Client.Token, InfluxModel.Client.Org);
        _bucketList = await InfluxModel.FetchBuckets();

        if (_bucketList.FirstOrDefault(bucket => bucket.Name == "iot_center") != null) SelectedBucket = "iot_center";
    }

    #region ---------------------------- ClientSettings ----------------------------

    private Client? _client;

    private ButtonStyle _checkConnectionButtonStyle = ButtonStyle.Light;

    private ButtonStyle CheckConnectionButtonStyle
    {
        get => _checkConnectionButtonStyle;
        set
        {
            _checkConnectionButtonStyle = value;
            switch (value)
            {
                case ButtonStyle.Success:
                    _buttonIcon = "check_circle";
                    break;
                case ButtonStyle.Danger:
                    _buttonIcon = "report";
                    break;
                default:
                    _buttonIcon = "save";
                    break;
            }
            StateHasChanged();
        }
    }

    private string _buttonIcon = "save";

    private bool _checkConnectionBusy;

    private bool CheckConnectionBusy
    {
        get => _checkConnectionBusy;
        set
        {
            _checkConnectionBusy = value;
            StateHasChanged();
        }
    }

    private async void CheckConnection()
    {
        CheckConnectionBusy = true;
        if (await InfluxModel.CheckClient(_client))
        {
            InfluxModel.Client.Org = _client?.Org;
            InfluxModel.Client.Token = _client?.Token;
            InfluxModel.Client.Url = _client?.Url;
            CheckConnectionButtonStyle = ButtonStyle.Success;
        }
        else
        {
            CheckConnectionButtonStyle = ButtonStyle.Danger;
        }
        CheckConnectionBusy = false;
    }

    #endregion ---------------------------- ClientSettings ----------------------------

    #region ---------------------------- DeviceRegistration ----------------------------

    private List<Bucket>? _bucketList;

    private string? _selectedBucket;

    string? SelectedBucket
    {
        get => _selectedBucket;
        set
        {
            _selectedBucket = value;
            FetchDevices(value).ConfigureAwait(false);
        }
    }

    private List<FluxRecord?>? _deviceList;

    private List<FluxRecord?>? DeviceList
    {
        get => _deviceList;
        set
        {
            _deviceList = value;
            StateHasChanged();
            if (value == null || value.Count < 1)
                SelectedDevice = "";
            else if (string.IsNullOrEmpty(SelectedDevice))
            {
                var device = value.FirstOrDefault(dev => dev!.Values.FirstOrDefault(rec => rec.Key == "deviceId").Value.ToString() == "virtual_device");
                if (device != null) SelectedDevice = device.Values.FirstOrDefault(rec => rec.Key == "deviceId").Value.ToString();
            }
        }
    }

    private string? _newDevice = "";

    private string? NewDevice
    {
        get => _newDevice;
        set
        {
            _newDevice = value;
            StateHasChanged();
        }
    }

    private async Task FetchDevices(string? value)
    {
        if (!string.IsNullOrEmpty(value))
        {
            var tables = await InfluxModel.FetchDeviceList(value);
            if (tables != null)
            {
                var records = tables.Select(table => table.Records
                    .FirstOrDefault(rec => rec.Values.ContainsKey("deviceId"))).ToList();
                DeviceList = records;
            }
        }
        else
        {
            DeviceList = new List<FluxRecord>()!;
        }
    }

    private bool _registerDeviceBusy;

    private bool RegisterDeviceBusy
    {
        get => _registerDeviceBusy;
        set
        {
            _registerDeviceBusy = value;
            StateHasChanged();
        }
    }

    private async void RegisterDevice()
    {
        RegisterDeviceBusy = true;
        if (!string.IsNullOrEmpty(SelectedBucket) && !string.IsNullOrEmpty(NewDevice))
        {
            await InfluxModel.CreateDevice(NewDevice, "virtual", SelectedBucket);
            await FetchDevices(SelectedBucket);
            NewDevice = "";
        }
        else if (string.IsNullOrEmpty(SelectedBucket))
            await JsRuntime.InvokeAsync<bool>("confirm", "Please select bucket.");
        else if (string.IsNullOrEmpty(NewDevice))
            await JsRuntime.InvokeAsync<bool>("confirm", "DeviceId cannot be empty.");

        RegisterDeviceBusy = false;
    }

    private bool _removeDeviceBusy;

    private bool RemoveDeviceBusy
    {
        get => _removeDeviceBusy;
        set
        {
            _removeDeviceBusy = value;
            StateHasChanged();
        }
    }

    private async Task RemoveDevice(FluxRecord record)
    {
        if (SelectedBucket != null)
        {
            RemoveDeviceBusy = true;
            if (await InfluxModel.RemoveDevice(record, SelectedBucket))
                await FetchDevices(SelectedBucket);
        }
        RemoveDeviceBusy = false;
    }

    private bool _refreshDevicesBusy;

    private bool RefreshDevicesBusy
    {
        get => _refreshDevicesBusy;
        set
        {
            _refreshDevicesBusy = value;
            StateHasChanged();
        }
    }

    private async Task RefreshDevices()
    {
        RefreshDevicesBusy = true;
        _bucketList = await InfluxModel.FetchBuckets();
        if (string.IsNullOrEmpty(SelectedBucket) &&
            _bucketList.FirstOrDefault(bucket => bucket.Name == "iot_center") != null)
            SelectedBucket = "iot_center";
        RefreshDevicesBusy = false;
    }

    #endregion ---------------------------- DeviceRegistration ----------------------------

    #region ---------------------------- DeviceDashboard ----------------------------

    private string? _selectedDevice;

    private string? SelectedDevice
    {
        get => _selectedDevice;
        set
        {
            _selectedDevice = value;
            StateHasChanged();
            RefreshData();
        }
    }

    private bool _writeEmulatedDataBusy;

    private bool WriteEmulatedDataBusy
    {
        get => _writeEmulatedDataBusy;
        set
        {
            _writeEmulatedDataBusy = value;
            StateHasChanged();
        }
    }

    private async void WriteEmulatedData()
    {
        WriteEmulatedDataBusy = true;
        if (SelectedBucket != null && !string.IsNullOrEmpty(SelectedDevice))
        {
            await InfluxModel.WriteEmulatedData(SelectedDevice, SelectedBucket);
            RefreshData();
        }
        WriteEmulatedDataBusy = false;
    }

    private bool _refreshDataBusy;

    private bool RefreshDataBusy
    {
        get => _refreshDataBusy;
        set
        {
            _refreshDataBusy = value;
            StateHasChanged();
        }
    }

    private async void RefreshData()
    {
        RefreshDataBusy = true;

        if (_chartDataList != null)
            foreach (var data in _chartDataList)
                await data.FetchDataMean(SelectedBucket, SelectedDevice);

        if (SelectedBucket != null && !string.IsNullOrEmpty(SelectedDevice))
            Measurements = await InfluxModel.FetchMeasurements(SelectedBucket, SelectedDevice);
        else Measurements = new List<FluxTable>();

        RefreshDataBusy = false;
    }

    private List<ChartData>? _chartDataList;

    private List<FluxTable>? _measurements;

    private List<FluxTable>? Measurements
    {
        get => _measurements;
        set
        {
            _measurements = value;
            StateHasChanged();
        }
    }

    #endregion ---------------------------- DeviceDashboard ----------------------------

    string FormatDateTime(object? value)
    {
        return value != null ? Convert.ToDateTime(value.ToString()).ToString(CultureInfo.InvariantCulture) : string.Empty;
    }

}